using UnityEngine;
using System.Collections.Generic;
using System.Collections;

namespace SangsTools
{
    public class PoolComponent<T> : IPool<T>, IEnumerable<T> where T : Component
    {
        protected readonly T prefab;

        protected readonly List<T> activeMembers;
        protected readonly Stack<T> unActiveMembers;

        public int Count => activeMembers.Count;

        public PoolComponent(T prefab)
        {
            if (prefab == null) throw new System.Exception("Prefab can not be Null!");

            this.prefab = prefab;

            activeMembers = new List<T>();
            unActiveMembers = new Stack<T>();
        }

        public T GetMember()
        {
            T member;
            if (unActiveMembers.Count > 0)
                member = unActiveMembers.Pop();
            else
                member = CreateMember();

            member.gameObject.SetActive(true);
            activeMembers.Add(member);
            return member;
        }

        public T GetMember(Transform parent)
        {
            T member = GetMember();
            member.transform.SetParent(parent);
            return member;
        }

        protected virtual T CreateMember()
        {
            if (prefab == null) return null;
            T member = MonoBehaviour.Instantiate(prefab.gameObject).GetComponent<T>();
            return member;
        }

        public void Recycle(T member)
        {
            if (member == null) throw new System.Exception("can not recycle null");

            if (activeMembers.Contains(member))
                activeMembers.Remove(member);
            if (!unActiveMembers.Contains(member))
                unActiveMembers.Push(member);

            member.transform.SetParent(null);
            member.gameObject.SetActive(false);
        }

        public void RecycleAll()
        {
            foreach (var member in activeMembers.ToArray())
            {
                Recycle(member);
            }
        }

        public void DestroyAll()
        {
            foreach (var item in activeMembers)
            {
                MonoBehaviour.Destroy(item.gameObject);
            }
            foreach (var item in unActiveMembers)
            {
                MonoBehaviour.Destroy(item.gameObject);
            }

            activeMembers.Clear();
            unActiveMembers.Clear();
        }

        public IEnumerator<T> GetEnumerator()
        {
            List<T> tmp = new List<T>();
            tmp.AddRange(activeMembers);
            tmp.AddRange(unActiveMembers);
            foreach (var item in tmp)
            {
                yield return item;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}